/**
 * Created by udi on 2016/11/26.
 */
'use strict'
var mongo = require('mongodb').MongoClient;
var ObjectId = require('mongodb').ObjectId;

let dbConfig = require("../../dbConfig").dbConfig;
let jv = require("libjv").default;
const logger = require('../../logger').logger;

let getConnectionUrl = () => `mongodb://${dbConfig.user}:${dbConfig.password}@${dbConfig.host}:${dbConfig.port}/${dbConfig.database}${global.planCode ? ('_' + global.planCode) : ''}`;

var logs = [];
let log = (msg) => {
    logs.push(msg)
}
let proc_where = (where) => {
    Object.keys(where).forEach(key => {
        var value = where[key];
        if ((key == "_id" || key.endsWith("._id")) && value && value.Type == "string" && value.length > 20 && ObjectId.isValid(value)) {
            where[key] = ObjectId(value);
        }
    });

    log("where: " + JSON.stringify(where));
    return where;
};
// let proc_where = (where) => {
//     Object.keys(where).forEach(key => {
//         var value = where[key];
//         if (key == "_id" && value && value.Type == "string" && ObjectId.isValid(value)) {
//             where[key] = ObjectId(value);
//         } else if (value.ObjectType) {
//             if( value._id && value._id.Type != "objectID"){
//             }else {
//                 proc_where(value);
//             }
//         }
//     });
//     return where;
// };

//记得最后  conn.close();
// let usingConnection = async (collectionName, callback) => {
//     var mongo2 = new mongo(url, {useNewUrlParser: true, useUnifiedTopology: true});
//     var client = await mongo2.connect();
//
//     let collection = collectionName && client.db().collection(collectionName);
//
//     var ret = await callback(collection, client);
//
//     client.close();
//     return ret;
// };

let usingConnection = async (collectionName, callback) => {
    return new Promise((resolve, reject) => {
        (new mongo(getConnectionUrl(), {useNewUrlParser: true, useUnifiedTopology: true})).connect((err, client) => {
            if (err) {
                return reject(err);
            }

            let collection = collectionName && client.db().collection(collectionName);
            log("using " + collectionName);

            return callback(collection, client).then(data => {
                resolve(data);
                client.close();
                logger.info(logs.join(" "))
                logs.length = 0;
                return data;
            });
        });
    });
};

let mongo_find = async (tab, where, skip, take) => {
    return await usingConnection(tab, collection => {
        return new Promise((r, e) => {
            var query = collection.find(proc_where(where));
            if (skip) {
                query.skip(skip);
            }
            if (take) {
                query.limit(take);
            }

            if (skip || take) {
                log("limit: " + skip + "," + take);
            }

            query.toArray((err, docs) => {
                if (err) {
                    return e(err);
                }

                return r(docs);
            })
        });
    });
};

let mongo_findOne = async (tab, where) => {
    let results = await mongo_find(tab, where, 0, 1);
    return results && results[0];
};

/**
 * for await ( var it of mor.readStreamEntity("tab",{} )){ }
 * @param tab
 * @param where
 * @param initSkip
 * @param batchSize
 * @returns {AsyncGenerator<*, void, ?>}
 */
async function* mongo_readStreamEntity(tab, where, initSkip, batchSize) {

    var skip = initSkip || 0;
    batchSize = batchSize || 25;
    var currentData = await mongo_find(tab, where, skip, batchSize);
    var current = 0;

    let next = async () => {
        if (currentData.length == 0) {
            return {done: true};
        }

        if (current.Between(0, currentData.length - 1)) {
            var ret = currentData[current];
            current++;
            return {done: false, value: ret};
        }

        if (currentData.size < batchSize) {
            return {done: true};
        }

        current = 0;

        skip += batchSize;

        currentData = await mongo_find(tab, where, skip, batchSize);
        if (currentData.length == 0) {
            return {done: true};
        }

        if (current.Between(0, currentData.length - 1)) {
            var ret = currentData[current];
            current++;
            return {done: false, value: ret};
        }

        return {done: true};
    };

    while (true) {
        var nextObj = await next();
        if (nextObj.done) break;
        yield nextObj.value;
    }
    //
    // return {
    //     [Symbol.iterator]: async () => {
    //
    //
    //         return {next}
    //     }
    // }
};

let mongo_update = async (tab, where, set) => {
    return await usingConnection(tab, collection => {
        log("update $set: " + JSON.stringify(set))
        return collection.updateMany(proc_where(where), {"$set": set}, true, true).then(ret => {
            if (ret.result.ok) {
                log("result: " + ret.result.n)
                return ret.result.n; // n是 where 条数， nModified:是影响行数
            }
            return null;
        });
    });
}

let mongo_insert = async (tab, entity) => {
    if (!entity._id) {
        entity._id = ObjectId();
    }
    return await usingConnection(tab, collection => {
        log("insert: " + JSON.stringify(entity))
        return collection.insertOne(entity).then(ret => {
            if (ret.result.ok) {
                log("result:" + ret.result.n);
                return ret.result.n; // n是 where 条数， nModified:是影响行数
            }
            return null;
        });
    });
}

let mongo_remove = async (tab, where) => {
    return await usingConnection(tab, collection => {
        log("delete: ")
        return collection.deleteMany(proc_where(where)).then(ret => {
            if (ret.result.ok) {
                log("result: " + ret.result.n)
                return ret.result.n; // n是 where 条数， nModified:是影响行数
            }
            return null;
        });
    });
}

let mongo_eval = async (command) => {
    return await usingConnection("", (_, client) => {
        log("eval: ")
        return client.eval(command).then(ret => {
            if (ret.result.ok) {
                log("result: " + ret.result.n)
                return ret.result.n; // n是 where 条数， nModified:是影响行数
            }
            return null;
        });
    });
};


exports.proc_where = proc_where;
exports.log = log;
exports.get = usingConnection;
exports.readStreamEntity = mongo_readStreamEntity;
exports.find = mongo_find;
exports.findOne = mongo_findOne;
exports.update = mongo_update;
exports.insert = mongo_insert;
exports.remove = mongo_remove;
exports.eval = mongo_eval;

